package com.zhuhjay.common.core.util;

import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTPayload;
import cn.hutool.jwt.JWTUtil;
import com.zhuhjay.common.base.config.SystemConfig;
import com.zhuhjay.common.base.util.SpringContextHolder;
import com.zhuhjay.common.redis.util.RedisIdWorker;
import com.zhuhjay.common.security.LoginUserDetail;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

import static com.zhuhjay.common.base.constant.ApplicationConstant.USER_UNIQUE_ID_KEY;
import static com.zhuhjay.common.base.constant.SecurityConstant.*;

/**
 * @author ZhuHJay
 * @date 2023/2/25 10:48
 */
public class JwtUtils {

    /** 续签阈值, 当 0.25 > (剩余时间/总时间) 时将可续签
     即剩余时间为 1/4 时将进行续签 **/
    private static final BigDecimal THRESHOLD = new BigDecimal("0.5");

    private static final String AUTHOR = SpringContextHolder.getBean(SystemConfig.class).getAuthor();

    /** 生成token **/
    public static String createToken(LoginUserDetail loginUserDetail) {
        Map<String, Object> payload = new HashMap<>(4);
        // 签发者
        payload.put(JWTPayload.ISSUER, AUTHOR);
        long uid = RedisIdWorker.nextId("token");
        payload.put(USER_UNIQUE_ID_KEY, uid);
        loginUserDetail.setUid(uid);
        // 设置过期时间
        refreshExpireTime(loginUserDetail);
        return JWTUtil.createToken(payload, JWT_SECRET_KEY.getBytes());
    }

    /** 刷新有效期时间 **/
    public static void refreshExpireTime(LoginUserDetail loginUserDetail) {
        LocalDateTime now = LocalDateTime.now();
        // 如果已经记录了登录时间, 那么不修改登录时间
        if (loginUserDetail.getLoginTime() == null) {
            loginUserDetail.setLoginTime(now);
        }
        loginUserDetail.setExpireTime(now.plusSeconds(JWT_EXPIRATION_TIME_UNIT.toSeconds(JWT_EXPIRATION_TIME)));
    }

    /** 获取用于响应的auth **/
    public static String takeRespAuth(String token) {
        return AUTH_RES_TITLE + token;
    }

    /** 解析token，返回token中的用户信息 */
    public static String parseToken(String token) {
        JWT jwt = JWTUtil.parseToken(token);
        JWTPayload payload = jwt.getPayload();
        return String.valueOf(payload.getClaim(USER_UNIQUE_ID_KEY));
    }

    /** 暴露token(清除载荷) **/
    public static String exportToken(String token) {
        // 获取真正的token
        return token.split(" ")[1];
    }

    /** 根据过期时间判断是否需要续签 **/
    public static boolean isRenew(LoginUserDetail loginUserDetail) {
        LocalDateTime expireTime = loginUserDetail.getExpireTime();
        LocalDateTime now = LocalDateTime.now();
        // 计算（剩余时间 / 总时间）   2/10 = 0.2
        BigDecimal result = new BigDecimal(Duration.between(now, expireTime).toNanos())
                .divide(new BigDecimal(JWT_EXPIRATION_TIME_UNIT.toNanos(JWT_EXPIRATION_TIME)), 2, RoundingMode.DOWN);
        // now expireTime && 0.25 > 0.2 即可续签
        return now.isBefore(expireTime) && THRESHOLD.compareTo(result) > 0;
    }

}
